﻿#include <time.h>
#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
#include <set>
#include <map>
#include <fstream>

#include "lua/ELuna.h"
#include "../libgate/fruit.h"
#include "../libgate/orange.h"
#include "../libgate/hp.h"

// #pragma comment(lib,"lua/lua51")

static void onCheckedSelf();
static void onReceive(int order, int type, const char* arr, int length);
static void onShutdown();

ccc_ptr_lock;
static HP_TcpPackClientListener pListener = nullptr;
static HP_TcpPackClient pSender = nullptr;
EnHandleResult __stdcall OnConnect(HP_Client pSender, CONNID dwConnID)
{
	ccc_en_lock;
	onCheckedSelf();
	ccc_un_lock;
	return HR_OK;
}
EnHandleResult __stdcall OnReceive(HP_Client pSender, CONNID dwConnID, const BYTE* pData, int iLength)
{
	ccc_en_lock;
	auto arr = easyOrange((unsigned char*)pData, iLength);
	if (arr == nullptr)
	{
		return HR_OK;
	}
	int order = *(int*)(arr);
	char type = *(arr + 4);
// 	std::ofstream ofile("_数据到达.log", std::ios::app);
// 	ofile << order << " " << (int)type << " " << std::string((char*)(arr + 5), iLength - 5) << "\n";
// 	ofile.close();
	onReceive(order, type, (char*)(arr + 5), iLength - 5);
	delete[] arr;
	ccc_un_lock;
	return HR_OK;
}
EnHandleResult __stdcall OnClose(HP_Client pSender, CONNID dwConnID, EnSocketOperation enOperation, int iErrorCode)
{
	ccc_en_lock;
	::Destroy_HP_TcpPackClient(pSender);
	::Destroy_HP_TcpClientListener(pListener);
	onShutdown();
	ccc_un_lock;
	return HR_IGNORE;
}

static lua_State* L = nullptr;
static void onCheckedSelf()
{
//	lua_pushcfunction(L, traceback);
//	int error_pos = lua_gettop(L);
	lua_getglobal(L, "onCheckedSelf");
//	lua_call(L, 0, 0);
	if (lua_pcall(L, 0, 0, 0) != 0)
	{
		std::cout << lua_tostring(L, -1) << std::endl;
		lua_pop(L, 1);
	}
}

void onRegiste(const char* toast)
{
	lua_getglobal(L, "onRegiste");
	lua_pushlstring(L, toast, strlen(toast));
	if (lua_pcall(L, 1, 0, 0) != 0)
	{
		std::cout << lua_tostring(L, -1) << std::endl;
		lua_pop(L, 1);
	}
}

static bool cc_registe(std::string& name, const char* content, int i, int mi, int ma)
{
	if (i < mi)
	{
		name += "太短";
		return false;
	}

	if (i > ma)
	{
		name + "太长";
		return false; 
	}
	for (int k = 0; k < i; ++k)
	{
		const auto& c = content[k];
		if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_')
		{

		}
		else
		{
			name += "不能有 空格 回车 特殊字符";
			return false;
		}
	}
	return true;
}

static void ccc_registe(int order, const char* account, const char* password, const char* safeword)
{
	std::string name = "账号";
	int icount = strlen(account);
	if (!cc_registe(name, account, icount, 6, 32))
	{
		return onRegiste(name.c_str());
	}
	name = "密码";
	int ipassword = strlen(password);
	if (!cc_registe(name, password, ipassword, 6, 32))
	{
		return onRegiste(name.c_str());
	}
	name = "安全码";
	int isafeword = strlen(safeword);
	if (!cc_registe(name, safeword, isafeword, 6, 32))
	{
		return onRegiste(name.c_str());
	}
	int length = icount + ipassword + isafeword;
	auto arr = new unsigned char[length];
	memcpy(arr, account, icount);
	memcpy(arr + icount, password, ipassword);
	memcpy(arr + icount + ipassword, safeword, isafeword);
	auto arr2 = toServer(0, order, icount, ipassword, isafeword, typeString, arr, length);
	delete[] arr;
	arr = eatApple(arr2, length);
	delete[] arr2;
	if (arr == nullptr)
	{
		return onRegiste("注册无效");
	}
	::HP_Client_Send(pSender, arr, length);
	delete[] arr;
	return onRegiste("");
}


static void onReceive(int order, int type, const char* arr, int length)
{
// 	std::cout << order << "   " << std::string(arr, length) << std::endl;
// 	return;
//	lua_pushcfunction(L, traceback);
//	int error_pos = lua_gettop(L);
	lua_getglobal(L, "onReceive");
	lua_pushinteger(L, order);
	lua_pushinteger(L, type);
	lua_pushlstring(L, arr, length);
	if (lua_pcall(L, 3, 0, 0) != 0)
	{
		if (lua_isstring(L, -1))
		{
			std::cout << lua_tostring(L, -1) << std::endl;
		}
		lua_pop(L, 1);
	}
}


static void onShutdown()
{
	lua_getglobal(L, "onShutdown");
	if (lua_pcall(L, 0, 0, 0) != 0)
	{
		if (lua_isstring(L, -1))
		{
			std::cout << lua_tostring(L, -1) << std::endl;
		}
		lua_pop(L, 1);
	}
}


// 先注册lua 再启动
static void ccc_start(const char* c, int port)
{
	if (pSender == nullptr)
	{
		pListener = ::Create_HP_TcpPackClientListener();
		pSender = ::Create_HP_TcpPackClient(pListener);
		::HP_Set_FN_Client_OnConnect(pListener, OnConnect);
		::HP_Set_FN_Client_OnReceive(pListener, OnReceive);
		::HP_Set_FN_Client_OnClose(pListener, OnClose);
		::HP_TcpPackClient_SetMaxPackSize(pSender, cFFF);
		::HP_TcpPackClient_SetPackHeaderFlag(pSender, 0x163);
	}
	if (::HP_Client_HasStarted(pSender) == FALSE)
	{
		::HP_Client_Start(pSender, c, port, TRUE);
	}
}


static int offtime = 0, gameRoleId = 0;
static void ccc_timeId(int offt, int roleId)
{
	offtime = offt;
	gameRoleId = roleId;
}


static void ccc_send(int order, int orderInner, int parameter, int type, const char* arr)
{
	int length = strlen(arr);
	auto arr2 = toServer(offtime, order, orderInner, parameter, gameRoleId, type, (unsigned char*)arr, length);
	auto arr3 = eatApple(arr2, length);
	delete[] arr2;
	if (arr3 == nullptr)
	{
		return;
	}
	::HP_Client_Send(pSender, arr3, length);
	delete[] arr3;
}

static void setCriticalSection(int cs)
{
	ccc_set_lock(cs);
}

// ELuna::Function_Vector ELuna::CPPGarbage::m_CPPFunctions;
// ELuna::Method_Vector   ELuna::CPPGarbage::m_CPPMethods;

#define rFunc(_func_) ELuna::registerFunction(L, #_func_, _func_)
#if 0
extern "C" __declspec(dllexport) int luaopen_libclient(lua_State* LL)
{
// 	static const luaL_Reg modulename [] = { {NULL,NULL} };
// 	luaL_register(LL, "testclient", modulename);
 	L = LL;
	rFunc(ccc_start);
	rFunc(ccc_timeId);
	rFunc(ccc_send);
	rFunc(ccc_registe);
	rFunc(setCriticalSection);

// 	const char* gname = "__testclient";
// 	ELuna::registerClass<hpclient>(L, gname, ELuna::constructor<hpclient>);
//  	ELuna::registerMethod<hpclient>(L, "start", &hpclient::ccc_start);
// 	ELuna::registerMethod<hpclient>(L, "send", &hpclient::ccc_send);
// 	ELuna::registerMethod<hpclient>(L, "registe", &hpclient::registe);
// 
// 	lua_getglobal(L, gname);
// 	lua_pushnil(L);
// 	lua_setglobal(L, gname);

//	InitializeCriticalSection(s_cs);

	return 1;
}
#else
extern CRITICAL_SECTION g_cs;
int REG_GGE_CLIENT(lua_State * LL) 
{
	L = LL;
	ccc_set_lock(&g_cs);
	rFunc(ccc_start);
	rFunc(ccc_timeId);
	rFunc(ccc_send);
	rFunc(ccc_registe);
	rFunc(setCriticalSection);

	return 1;
}
#endif